home *** CD-ROM | disk | FTP | other *** search
/ Visual Basic Source Code / Visual Basic Source Code.iso / vbsource / metkit / catfish.cpp < prev    next >
C/C++ Source or Header  |  1997-06-07  |  43KB  |  1,418 lines

  1. //    Copyright (C) 1996, 1997 Meta Four Software.  All rights reserved.
  2. //
  3. //  Main CatFish application sample code
  4. //
  5. //! rev="$Id: catfish.cpp,v 1.5 1997/05/27 00:06:05 jcw Rel $"
  6.  
  7. #include "stdafx.h"
  8. #include "catfish.h"
  9. #include "setupdlg.h"
  10.  
  11.     #include <dos.h>    // _dos_findfirst in GetCatalogDate
  12.     
  13. #ifdef _DEBUG
  14. #undef THIS_FILE
  15. static char BASED_CODE THIS_FILE[] = __FILE__;
  16. #endif
  17.  
  18. #pragma warning(disable: 4702) // MSVC 1.52 gets confused: unreachable code
  19.     
  20. /////////////////////////////////////////////////////////////////////////////
  21. // MSDN Q100770: Using Accelerator Keys When Modal Dialog Box Main Window
  22.  
  23.     HWND    ghDlg;          // Handle to main dialog box
  24.     HACCEL  ghAccelTable;   // Handle to accelerator table
  25.  
  26.     CTheApp ThisApp;
  27.  
  28. /////////////////////////////////////////////////////////////////////////////
  29. // Use a simple version of localized date, time, and number formating.
  30.  
  31.     static CString  sShortDate  = "MM/dd/yy";   // "d.M.yyyy", etc
  32.     static bool     iTime       = false;        // true if 24h format
  33.     static bool     iTLZero     = true;         // true if hour has 2 digits
  34.     static char     sThousand   = ',';          // thousands separator
  35.     static char     sTime       = ':';          // time separator
  36.  
  37.     static void SetInternationalSettings()
  38.     {
  39.         iTime = GetProfileInt("intl", "iTime", 0) != 0;
  40.         iTLZero = GetProfileInt("intl", "iTLZero", 1) != 0;
  41.         
  42.         char buf [30];
  43.         
  44.         if (GetProfileString("intl", "sShortDate", "MM/dd/yy", buf, sizeof buf))
  45.             sShortDate = buf;
  46.         
  47.         if (GetProfileString("intl", "sThousand", ",", buf, sizeof buf))
  48.             sThousand = *buf;
  49.         
  50.         if (GetProfileString("intl", "sTime", ":", buf, sizeof buf))
  51.             sTime = *buf;
  52.     }
  53.         
  54. /////////////////////////////////////////////////////////////////////////////
  55. // Convert a number to comma-separated format, grouped in units of three.
  56. // Optionally prefix with spaces (assuming two spaces is width of one digit).
  57. // Finally, the zero value can be changed to a '-' upon request.
  58. //
  59. // Note:    In many places, the code is simplified by the assumption that
  60. //          every digit has exactly the same width as two space characters.
  61. //          This works for the selected font (MS Sans Serif, font size 8).
  62. //          It allows us to present a nice columnar interface without having
  63. //          to figure out each of the string position in pixels. There are
  64. //          several more assumptions like this (e.g. "k   " is like "Mb").
  65.  
  66.     static CString CommaNum(DWORD num, int groups =0, BOOL zero =TRUE)
  67.     {
  68.         CString s;
  69.         s.Format("%lu", num);
  70.         
  71.         int g = 0;
  72.         int n = s.GetLength();
  73.         while (n > 3)
  74.         {
  75.             n -= 3;
  76.             s = s.Left(n) + sThousand + s.Mid(n);
  77.             ++g;
  78.         }
  79.         
  80.         if (--groups >= 0)
  81.         {
  82.             int w = ((3 - n) % 3) * 2;
  83.             if (g < groups)
  84.                 w += 7 * (groups - g);
  85.  
  86.             s = CString (' ', w) + s;
  87.         }
  88.         
  89.         if (!zero && (s == "0" || s.Right(2) == " 0"))
  90.             s = s.Left(s.GetLength() - 1) + " -";
  91.             
  92.         return s;
  93.     }
  94.     
  95. /////////////////////////////////////////////////////////////////////////////
  96. // Convert a DOS date and TIME words to short format strings.
  97. // Lets be nice to a lot of people and adopt their local conventions.
  98.  
  99.     static CString ShortDate(WORD date)
  100.     {
  101.         if (date == 0)
  102.             return "";  // will be ok as long as the date is last item
  103.             
  104.         int w = 0;
  105.         
  106.         char buf [10];
  107.         char* q = buf;
  108.         
  109.             // decode the short date, deal with 1- and 2-digit fields
  110.         const char* p = sShortDate;
  111.         while (*p)
  112.         {
  113.             int i;
  114.             
  115.             switch (*p++)
  116.             {            
  117.                 default:    *q++ = *(p-1);
  118.                             continue;
  119.                 
  120.                 case 'd':   i = date & 0x1F;
  121.                             break;
  122.                             
  123.                 case 'M':   i = (date >> 5) & 0x0F;
  124.                             break;
  125.                             
  126.                 case 'y':   i = ((date >> 9) + 80) % 100;
  127.                             break; // 4-digit years are treated as 2-digit
  128.                             
  129.             }
  130.             
  131.             if (i < 10 && *p != *(p-1))
  132.                 ++w;
  133.             else
  134.                 *q++ = (char) (i / 10 + '0');
  135.             
  136.             *q++ = (char) (i % 10 + '0');
  137.  
  138.             while (*p == *(p-1))
  139.                 ++p;
  140.         }
  141.         
  142.             // centering is easy, since one digit is as wide as two spaces
  143.         CString t (' ', 2 * w);
  144.             // alignment depends on whether the year is first or last 
  145.         if (sShortDate[0] == 'y')
  146.             return CString (buf, q - buf) + t;
  147.         
  148.         return t + CString (buf, q - buf);
  149.     }
  150.     
  151.     static CString ShortTime(WORD time)
  152.     {
  153.         int h = time >> 11;
  154.         int m = (time >> 5) & 0x3F;
  155.         char ampm = "ap" [h / 12];
  156.         
  157.         if (!iTime)
  158.             h = (h + 11) % 12 + 1; // dec, then inc, so 0 becomes 12
  159.             
  160.         CString s;
  161.         s.Format("%02d%c%02d", h, sTime, m);
  162.         
  163.         if (!iTime)
  164.             s += ampm;
  165.         
  166.         if (!iTLZero && s[0] == '0')
  167.             s = "  " + s.Mid(1); // replace leading zero with two spaces
  168.             
  169.         return s;
  170.     }
  171.     
  172. /////////////////////////////////////////////////////////////////////////////
  173. // Make a string fit in the specified number of pixels on given device.
  174. // Characters at the end are replaced by an ellipsis to make the string fit.
  175. // There is some trickery in here to optimize this very common calculation.
  176.  
  177.     static BOOL FitString(CDC* dc, CString& text, int width)
  178.     {
  179.         CSize sz = dc->GetTextExtent(text, text.GetLength());
  180.         if (sz.cx <= width)
  181.             return TRUE;    // make the most common case fast
  182.         
  183.             // Assumption: "...xyz" is just as wide as "xyz..." 
  184.         CString s = "..." + text;
  185.         
  186.         int n = s.GetLength();
  187.         while (--n > 3)
  188.         {            
  189.             sz = dc->GetTextExtent(text, n);
  190.             if (sz.cx <= width)
  191.                 break;
  192.         }
  193.              
  194.         text = text.Left(n - 3) + "...";
  195.         return FALSE;
  196.     }
  197.     
  198. /////////////////////////////////////////////////////////////////////////////
  199. // Disables redraw and clears listbox, will reset normal state in destructor
  200.  
  201.     class ListBoxFreezer
  202.     {
  203.     public:
  204.         ListBoxFreezer (CListBox& lb)
  205.             : list (lb)
  206.         {
  207.             list.SetRedraw(FALSE);
  208.             list.ResetContent();
  209.         }
  210.         
  211.         ~ListBoxFreezer ()
  212.         {
  213.             list.SetRedraw(TRUE);
  214.             list.Invalidate();
  215.         }
  216.     
  217.     private:
  218.         CListBox& list;
  219.     };
  220.     
  221. /////////////////////////////////////////////////////////////////////////////
  222. // Return file date in display format, or an empty string if file not present
  223.  
  224. CString GetCatalogDate(CString& catName)
  225. {
  226.     CString s = catName;
  227.     s += FILE_TYPE;
  228.  
  229. #ifndef _WIN32
  230.     _find_t fbuf;
  231.     if (_dos_findfirst(s, _A_NORMAL, &fbuf) != 0)
  232.         return "";
  233.     
  234.         // pick up the name as it is stored on disk (properly capitalized)
  235.     s = fbuf.name;
  236.     ASSERT(s.Right(4).CompareNoCase(FILE_TYPE) == 0);
  237.     catName = s.Left(s.GetLength() - 4);
  238.         
  239.     return ShortDate((WORD) fbuf.wr_date) + "  "
  240.             + ShortTime((WORD) fbuf.wr_time);
  241. #endif
  242.     return "?";
  243. }
  244.  
  245. /////////////////////////////////////////////////////////////////////////////
  246. // The one and only application object
  247.  
  248. CTheApp::CTheApp ()
  249.     : CWinApp ("CatFish")
  250. {    
  251. }
  252.  
  253. BOOL CTheApp::InitInstance()
  254. {
  255.     SetDialogBkColor();
  256.     SetInternationalSettings();
  257.  
  258.     ghAccelTable = LoadAccelerators(